10 REM *** (FFT7.02) FFT/INV FFT ***

11 REM MODIFIES TRIANGLE FUNCTION SPECTRUM & RECONSTRUCTS

12 SCREEN 9, 1: COLOR 15, 1

GOSUB 10000

13 CLS : PRINT : PRINT "INPUT NUMBER OF DATA POINTS AS 2^N"

14 INPUT "N = "; N

16 Q = 2 ^ N

20 Q2 = Q / 2: Q3 = Q2 - 1: Q4 = Q / 4: Q5 = Q4 - 1: Q8 = Q / 8

21 FMN = 0: FMX = Q: FSTEP = 1

22 DIM Y(Q), C(2, Q), S(2, Q), KC(Q), KS(Q), F(2, (FTOP - FBOT) + 1)

23 DIM COMP(3, KB, KB), Z(2, KB, KB + 1)

24 X0 = 50: Y0 = 200: XSF = 500 / Q: YSF = 150: IOFLG = 1

30 PI = 3.141592653589793#: P2 = 2 * PI: K1 = P2 / Q: PI2 = P2

32 FOR I = 0 TO Q: KC(I) = COS(K1 * I): KS(I) = SIN(K1 * I): NEXT

40 CLS

50 PRINT SPC(30); "MAIN MENU": PRINT : PRINT

52 PRINT SPC(5); "1 = GENERATE TRIANGLE FUNCTION & TRANSFORM": PRINT

54 PRINT SPC(5); "2 = FORWARD TRANSFORM": PRINT

56 PRINT SPC(5); "3 = MODIFY SPECTRUM": PRINT

58 PRINT SPC(5); "4 = INVERSE TRANSFORM": PRINT

60 PRINT SPC(5); "5 = MODIFY SYSTEM": PRINT

62 PRINT SPC(5); "6 = EXIT": PRINT

70 PRINT SPC(10); "MAKE SELECTION :";

80 A$ = INKEY$: IF A$ = "" THEN 80

90 A = VAL(A$): ON A GOSUB 600, 100, 1000, 120, 140, 990

95 GOTO 40



100 REM *** FORWARD FFT ***

102 K6 = -1: SK1 = 2

104 CLS : HDR$ = "FREQ   F(COS)       F(SIN)       "

106 HDR$ = HDR$ + "FREQ   F(COS)       F(SIN)": PRINT : PRINT

108 GOSUB 180

RETURN



120 REM *** INVERSE TRANSFORM ***

122 SK1 = 1: K6 = 1

124 CLS : HDR$ = "TIME    AMPLITUDE   NOT USED     "

126 HDR$ = HDR$ + "TIME   AMPLITUDE     NOT USED": PRINT : PRINT

128 GOSUB 180

130 RETURN



140 CLS ' *** MODIFY SYSTEM PARAMETERS ***

142 PRINT "PRESENT DATA GRAPHICALLY? (Y/N):";

144 A$ = INKEY$: IF A$ = "" THEN 144

146 IF A$ = "Y" OR A$ = "y" THEN IOFLG = 1 ELSE IOFLG = -1

148 RETURN



180 REM *** FFT ROUTINE ***

181 T9 = TIMER

182 FOR M = 0 TO N - 1: QT = 2 ^ M: KT1 = 2 ^ (N - M - 1)

183 REM *** UNIVERSAL BUTTERFLY ***

184 FOR J = 0 TO Q3 STEP QT: J1 = 2 * J: K9 = J + Q2

185 FOR I = 0 TO QT - 1: KT = I * KT1: K = K9 + I

187 C(T0, J1 + I) = (C(T1, I + J) + C(T1, K) * KC(KT) - K6 * S(T1, K) * KS(KT)) / SK1

188 S(T0, J1 + I) = (S(T1, I + J) + K6 * C(T1, K) * KS(KT) + S(T1, K) * KC(KT)) / SK1

190 NEXT I

191 J1 = J1 + QT

192 FOR I = 0 TO QT - 1: KT = (I + QT) * KT1: K = K9 + I

194 C(T0, J1 + I) = (C(T1, I + J) + C(T1, K) * KC(KT) - K6 * S(T1, K) * KS(KT)) / SK1

195 S(T0, J1 + I) = (S(T1, I + J) + K6 * C(T1, K) * KS(KT) + S(T1, K) * KC(KT)) / SK1

196 NEXT I: NEXT J

197 T0 = 1 - T0: T1 = 1 - T0

199 NEXT M



200 T9 = TIMER - T9

202 IF IOFLG = 1 THEN 250

206 ZSTP = 15

208 PRINT HDR$: PRINT : PRINT

210 FOR Z = 0 TO Q2 - 1

214 GOSUB 300

216 IF Z > ZSTP THEN 350 ' PRINT 1 SCREEN AT A TIME

220 NEXT Z

222 LOCATE 1, 1: PRINT : PRINT "TIME ="; T9

225 INPUT "C/R TO CONTINUE:"; A$

229 RETURN



250 REM *** PLOT OUTPUT ***

252 CLS : YPX = 0: IF K6 = -1 THEN 280

254 Y0 = 175

256 FOR I = 0 TO Q - 1 ' FIND MAX VALUE IN ARRAY

258 IF ABS(C(T1, I)) > YPX THEN YPX = ABS(C(T1, I))' IF > YPX SWAP

260 NEXT I ' CHECK NEXT DATA POINT

262 YSF = 100 / YPX' SET Y SCALE FACTOR

263 LINE (X0 + 10, Y0 - 100)-(X0, Y0 - 100)

264 LOCATE 6, 1: PRINT USING "###.##"; YPX ' PRINT SCALE FACTOR

265 LINE (X0 - 1, 50)-(X0 - 1, 300)

266 LINE (X0, Y0)-(X0 + 500, Y0)

268 LINE (X0, Y0)-(X0, Y0) ' PEN TO ORIGIN

270 FOR I = 0 TO Q - 1

272 YP = C(T1, I)

274 IF K6 = -1 THEN YP = SQR(C(T1, I) ^ 2 + S(T1, I) ^ 2)

276 LINE -(X0 + XSF * I, Y0 - YSF * YP)

278 NEXT I

279 GOTO 222

280 ' *** FIND Y SCALE FACTOR FOR FREQ DOMAIN PLOT ***

281 Y0 = 300 ' SET Y AXIS ORIGIN

282 FOR I = 0 TO Q - 1' FIND LARGEST VALUE IN ARRAY

284 YP = SQR(C(T1, I) ^ 2 + S(T1, I) ^ 2): IF YP > YPX THEN YPX = YP

286 NEXT I ' CHECK NEXT DATA POINT

287 YSF = 200 / YPX' SET SCALE FACTOR

288 LINE (X0 + 10, Y0 - 200)-(X0, Y0 - 200)

289 LOCATE 8, 1: PRINT USING "###.##"; YPX: GOTO 265



300 PRINT USING "###"; Z; : PRINT "   ";

310 PRINT USING "+##.#####"; C(T1, Z); : PRINT "    ";

312 PRINT USING "+##.#####"; S(T1, Z); : PRINT "      ";

320 PRINT USING "###"; Z + Q2; : PRINT "   ";

322 PRINT USING "+##.#####"; C(T1, Z + Q2); : PRINT "    ";

324 PRINT USING "+##.#####"; S(T1, Z + Q2)

330 RETURN



350 REM ***  STOP WHEN SCREEN FULL  ***

352 ZSTP = ZSTP + 16

354 PRINT : INPUT "ENTER TO CONTINUE:"; A$

356 CLS : PRINT HDR$: PRINT : PRINT

358 GOTO 220



600 REM * TRIANGLE FUNCTION *

602 CLS : PRINT : PRINT

604 PRINT "PREPARING DATA INPUT - PLEASE WAIT!"

FOR I = 1 TO Q2 - 1 STEP 2

C(0, I - 1) = 0: S(0, I - 1) = 0

C(0, I) = -1 / (I * I): S(0, I) = 0

C(0, Q - (I - 1)) = 0: S(0, Q - (I - 1)) = 0

C(0, Q - I) = -1 / (I * I): S(0, Q - I) = 0

NEXT I

C(0, Q2) = 0: S(0, Q2) = 0

T0 = 1: T1 = 0: K6 = -1

GOSUB 200

GOTO 690

610 FOR I = 0 TO Q / 2 - 1

620 C(0, I) = 1: S(0, I) = 0

630 NEXT

640 FOR I = Q / 2 TO Q - 1

650 C(0, I) = 0: S(0, I) = 0

660 NEXT

670 T0 = 1: T1 = 0

680 GOSUB 100

690 RETURN



990 END



1000 REM ***************************************

1002 REM *           MODIFY SPECTRUM           *

1004 REM ***************************************

1040 CLS : RTFLG = 0

1042 IF K6 <> -1 THEN 1096

1050 PRINT SPC(30); "MODIFY SPECTRUM MENU": PRINT : PRINT

1060 PRINT SPC(5); "1 = TRUNCATE SPECTRUM": PRINT

1062 PRINT SPC(5); "2 = BUTTERWORTH RESPONSE": PRINT

1064 PRINT SPC(5); "3 = GAUSSIAN RESPONSE": PRINT

1066 PRINT SPC(5); "4 = FREQUENCY SHIFT SPECTRUM": PRINT

1067 PRINT SPC(5); "5 = STRETCH SPECTRUM": PRINT

1068 PRINT SPC(5); "6 = EXIT": PRINT

1070 PRINT SPC(10); "MAKE SELECTION :";

1080 A$ = INKEY$: IF A$ = "" THEN 1080

1082 A = VAL(A$): ON A GOSUB 1100, 1200, 1300, 1400, 1500, 1990

1084 GOSUB 200

1088 IF RTFLG = 1 THEN RETURN

1090 GOTO 1040

1096 INPUT "MUST TRANSFORM SIGNAL BEFORE MODIFYING SPECTRUM"; A$

1098 RETURN



1100 REM * TRUNCATE SPECTRUM *

1102 CLS : PRINT : PRINT

1104 INPUT "ENTER DECIMAL FRACTION OF SPECTRUM TO REMOVE (I.E. 0.25)"; A$

1110 FC0 = VAL(A$): IF FC0 = 0 OR FC0 = 1 THEN 1104

1120 FCO = INT(Q2 * FC0 + .5)

1130 FOR I = Q2 - FCO TO Q2 + FCO

1140 C(T1, I) = 0: S(T1, I) = 0

1150 NEXT I

1194 RTFLG = 1: RETURN



1200 REM * BUTTERWORTH RESPONSE *

1202 CLS : PRINT : PRINT

1204 PRINT "ENTER THE 3db CUTOFF HARMONIC NUMBER (1 TO "; Q3; ")";

1206 INPUT A$

1208 FC0 = VAL(A$): IF FC0 = 0 OR FC0 > Q3 THEN 1204

1210 NP = 5: REM NUMBER OF POLES = NP

1220 FOR I = 1 TO Q3

1222 ATTN = 1 / SQR(1 + (I / FC0) ^ (2 * NP))

1224 C(T1, I) = ATTN * C(T1, I): S(T1, I) = ATTN * S(T1, I)

1226 C(T1, Q - I) = ATTN * C(T1, Q - I): S(T1, Q - I) = ATTN * S(T1, Q - I)

1228 NEXT I

1230 ATTN = 1 / SQR(1 + (Q2 / FC0) ^ (2 * NP))

1234 C(T1, Q2) = ATTN * C(T1, Q2)

1294 RTFLG = 1: RETURN



1300 REM * GAUSSIAN RESPONSE *

1302 CLS : PRINT : PRINT

1304 PRINT "ENTER THE 3db CUTOFF HARMONIC NUMBER (1 TO "; Q3; ")";

1306 INPUT A$

1308 FC0 = VAL(A$): IF FC0 = 0 OR FC0 > Q3 THEN 1304

1320 FOR I = 1 TO Q3

1322 ATTN = 1 / SQR(EXP(.3 * ((I / FC0) ^ 2)))

1324 C(T1, I) = ATTN * C(T1, I): S(T1, I) = ATTN * S(T1, I)

1326 C(T1, Q - I) = ATTN * C(T1, Q - I): S(T1, Q - I) = ATTN * S(T1, Q - I)

1328 NEXT I

1330 ATTN = 1 / SQR(EXP(.3 * ((Q2 / FC0) ^ 2)))

1334 C(T1, Q2) = ATTN * C(T1, Q2): S(T1, Q2) = ATTN * S(T1, Q2)

1394 RTFLG = 1: RETURN



1400 REM * FREQUENCY SHIFT *

1402 CLS : PRINT : PRINT

1404 ' INPUT "SHIFT UP OR DOWN (U/D)"; A$

1406 ' IF A$ = "U" OR A$ = "u" THEN 1420

1408 ' PRINT "CAN ONLY DO UP SHIFT FOR THE MOMENT"

1410 ' GOTO 1404

1420 REM SHIFT FREQUENCY UP

1422 FOR I = Q TO 1 STEP -1

1424 C(T1, I) = C(T1, I - 1): S(T1, I) = S(T1, I - 1)

1426 NEXT I

1428 C(T1, 0) = C(T1, Q): S(T1, 0) = S(T1, Q)

1430 PRINT "MORE (Y/N)";

1432 A$ = INKEY$: IF A$ = "" THEN 1432

1434 IF A$ = "Y" OR A$ = "y" THEN 1422

1440 RTFLG = 1: RETURN



' ***   STRETCH SPECTRUM   ***

1500 FOR I = Q4 TO 1 STEP -1: I2 = 2 * I: I3 = I2 - 1

C(T1, I2) = C(T1, I): S(T1, I2) = S(T1, I)

C(T1, I3) = 0: S(T1, I2) = 0

C(T1, Q - I2) = C(T1, Q - I): S(T1, Q - I2) = S(T1, Q - I)

C(T1, Q - I3) = 0: S(T1, Q - I3) = 0

NEXT I

RTFLG = 1: RETURN





1990 REM * EXIT MODIFY SPECTRUM ROUTINE *

1992 RTFLG = 1: RETURN



10000 CLS : PRINT : PRINT ' INFORMATION

PRINT "THE BEST ILLUSTRATION WILL BE FOR N = 8 (Q = 256). "

PRINT

PRINT "1) TRANSFORM THE TRIANGLE WAVE AND RECONSTRUCT (TO VERIFY PROPER OPERATION)."

PRINT

PRINT "2) GENERATE AND TRANSFORM THE TRIANGLE WAVE AGAIN, SELECT THE MODIFY"

PRINT "SPECTRUM MENU, AND SHIFT THE FREQUENCY UP 32 HARMONIC COMPONENTS "

PRINT "(i.e., REPEAT THE 'Y' KEY 32 TIMES).  EXIT TO THE MAIN MENU,"

PRINT "INVERSE TRANSFORM THE DATA AND OBSERVE THE MODULATED 'CARRIER'."

PRINT

PRINT "3) GENERATE AND TRANSFORM THE TRIANGLE WAVE AGAIN, SELECT THE MODIFY"

PRINT "SPECTRUM MENU, AND STRETCH THE SPECTRUM.  NEXT YOU MUST SELECT THE "

PRINT "MODIFY SPECTRUM MENU AGAIN, SHIFT THE FREQUENCY UP 32 HARMONIC"

PRINT "COMPONENTS (REPEAT THE 'Y' KEY 32 TIMES) AND EXIT TO THE MAIN MENU."

PRINT "INVERSE TRANSFORM THE DATA AND OBSERVE TWO CYCLES OF MODULATED CARRIER."

PRINT : PRINT

INPUT "ENTER TO CONTINUE"; A$

RETURN



